import math
import os
from typing import Dict, List

import meilisearch
import meilisearch.task

from apps.blog.models import Article, ArticleStatus


class SearchService:
    def __init__(self):
        self.endpoint = os.getenv("MEILISEARCH_URL")
        self.api_key = os.getenv("MEILISEARCH_API_KEY")
        self.client = meilisearch.Client(self.endpoint, self.api_key)
        self.index_name = "articles"
        self._ensure_index()

    def _ensure_index(self) -> None:
        """确保索引存在"""
        try:
            self.index = self.client.get_index(self.index_name)
        except Exception:
            # 创建索引并获取任务信息
            task = self.client.create_index(self.index_name)
            # 等待任务完成
            self.client.wait_for_task(task.task_uid)
            # 确认任务成功后获取索引
            task_info = self.client.get_task(task.task_uid)
            if task_info.status != "succeeded":
                raise Exception(
                    f"Failed to create index: {task_info.error.message if task_info.error else 'Unknown error'}"
                )

            # 重新获取索引对象
            self.index = self.client.get_index(self.index_name)

        # 更新可搜索属性
        update_task = self.index.update_searchable_attributes(
            ["title", "content", "description"]
        )
        # 等待更新完成
        self.client.wait_for_task(update_task.task_uid)

    async def rebuild_index(self) -> Dict:
        """重建文章索引"""
        # 删除所有现有文档

        self.index.delete_all_documents()
        articles = await Article.filter(
            active=True, status=ArticleStatus.PUBLISHED.value
        ).all()
        if not articles:
            return None

        # 准备文档数据
        documents = [
            {
                "id": str(article.id),  # Meilisearch 要求 id 为字符串
                "title": article.title,
                "content": article.content,
                "description": article.description,
            }
            for article in articles
        ]
        return self.index.add_documents(documents)

    async def search_articles(
        self, query: str, limit: int = 10, offset: int = 0
    ) -> Dict:
        """搜索文章"""
        search_result = self.index.search(
            query,
            {
                "limit": limit,
                "offset": offset,
                "attributesToHighlight": ["title", "content"],
                "attributesToCrop": ["content"],
                "cropLength": 200,
            },
        )
        total = search_result["estimatedTotalHits"]
        items = [item["_formatted"] for item in search_result["hits"]]
        pages = math.ceil(total / limit)
        return {
            "items": items,
            "pages": pages,
            "total": total,
            "page": offset,
            "size": limit,
        }

    def add_article(self, article: Article) -> Dict:
        """添加单个文章到索引"""
        doc = {
            "id": str(article.id),
            "title": article.title,
            "content": article.content,
            "description": article.description,
        }
        return self.index.add_documents([doc])

    def update_article(self, article: Article) -> Dict:
        """更新文章索引"""
        return self.add_article(article)

    def delete_article(self, article_id: str | List[str]) -> Dict:
        """删除文章索引"""
        if isinstance(article_id, str):
            return self.index.delete_document(article_id)
        return self.index.delete_documents(article_id)

    def delete_index(self) -> None:
        """删除索引"""
        self.client.delete_index(self.index_name)


# 创建搜索服务实例
search_service = SearchService()
